package com.bootdo.app.common.utils;


import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
  * @auther: Along
  * @description: 签名工具类
  */
public class SignUtil {

    public static final String SIGN_NAME = "MD5";
    public static final String SIGN_CHARSET = "UTF-8";
    public static final String SALT = "FH=UD*HHAj~HD#";

    /**
     * 从请求参数中获取签名内容
     * @param params 请求参数
     * @return
     */
    public static String getSignContent(Map<String,Object> params) {
        if (params == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            Object value = params.get(key);
            if ((key!=null && key.length()>0) && value!=null) {
                sb.append((i == 0 ? "" : "&") + key + "=" + value);
            }
        }
        return sb.toString();
    }

    /**
     * 从请求参数中获取验签内容
     * @param params 请求参数
     * @return
     */
    public static String getSignCheckContent(Map<String,Object> params) {
        if (params == null) {
            return "";
        }
        params.remove("sign");
        params.remove("signName");
        StringBuffer sb = new StringBuffer();
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            Object value = params.get(key);
            sb.append((i == 0 ? "" : "&") + key + "=" + value);
        }
        return sb.toString();
    }

    /**
     * 使用UTF8字符编码进行MD5签名
     * @param params 请求参数
     * @param salt 盐值
     * @return
     */
    public static String md5ContentSign_UTF8(Map<String,Object> params,String salt){
        return md5ContentSign(params,salt,SIGN_CHARSET);
    }

    /**
     * md5签名
     * @param params 请求参数
     * @param salt 盐值
     * @param charset 字符集编码
     * @return
     */
    public static String md5ContentSign(Map<String,Object> params,String salt,String charset){
        return md5ContentSign(getSignContent(params),salt,charset);
    }



    /**
     * md5 签名
     * @param content 待签名内容
     * @param salt 盐值
     * @param charset 字符集编码
     * @return
     */
    public static String md5ContentSign(String content,String salt,String charset){
        try{
            MessageDigest md = MessageDigest.getInstance(SIGN_NAME);
            content = content + salt;
            if(charset == null || "".equals(charset.trim()) || "null".equalsIgnoreCase(charset.trim())){
                md.update(content.getBytes());
            }else{
                md.update(content.getBytes(charset));
            }
            byte[] digest = md.digest();
            StringBuffer sb = new StringBuffer();
            int b;
            for(int i = 0; i < digest.length; i++){
                b = digest[i];
                if(b < 0){
                    b += 256;
                }
                if(b < 64){
                    sb.append("0");
                }
                sb.append(Integer.toHexString(b));
            }
            return sb.toString().toUpperCase();
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * md5 验签
     * @param content 签名数据
     * @param salt 盐值
     * @param sign 签名
     * @param charset 字符集编码
     * @return
     */
    public static boolean md5CheckContent(String content,String salt,String sign,String charset) {
        try {
            content = content + salt;
            MessageDigest md = MessageDigest.getInstance(SIGN_NAME);
            if (charset == null || "".equals(charset.trim()) || "null".equalsIgnoreCase(charset.trim())) {
                md.update(content.getBytes());
            } else {
                md.update(content.getBytes(charset));
            }
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer();
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 64)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            if (buf.toString().toUpperCase().equals(sign)) {
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 移除 sign & signName 用UTF-8编码验签
     * @param params 请求参数
     * @param salt 盐值
     * @return
     */
    public static boolean md5CheckUTF8(Map<String, Object> params, String salt)  {
        String sign = String.valueOf(params.get("sign"));
        String content = getSignCheckContent(params);
        return md5CheckContent(content,salt,sign,SIGN_CHARSET);
    }




    public static void main(String[] args) {
        /*
        String salt = "294*&(iu(#UR";

        Map<String,Object> params = new HashMap<>();
        params.put("code",200);
        params.put("msg","test");
        // 方式1
//        // 签名
        final String sign = md5ContentSign(params, salt, SIGN_CHARSET);
        params.put("sign",sign);
        params.put("signName",SIGN_NAME);

        // 开始验签
        final boolean b = md5CheckUTF8(params, salt);
        System.out.println("b = " + b);

        // 方式2
        // 获取签名内容
        final String signContent = getSignContent(params);
        // 签名
        final String sign_2 = md5ContentSign(signContent, salt, SIGN_CHARSET);
        final boolean b_2 = md5CheckContent(signContent, salt, sign_2, SIGN_CHARSET);
        System.out.println("b_2 = " + b_2);
        */

        // ----------
        String password = "123456";
        final String sign = md5ContentSign(password, SALT, SIGN_CHARSET);
        final String sign2 = md5ContentSign(password, SALT, SIGN_CHARSET);
        System.out.println("sign = " + sign);
        System.out.println("sign2 = " + sign2);

        final boolean b = md5CheckContent(password, SALT, sign, SIGN_CHARSET);
        System.out.println("b = " + b);

    }

}
